package com.ztp.android.usermanager;

import java.util.ArrayList;

import org.apache.ftpserver.FtpServerConfigurationException;
import org.apache.ftpserver.ftplet.Authentication;
import org.apache.ftpserver.ftplet.AuthenticationFailedException;
import org.apache.ftpserver.ftplet.Authority;
import org.apache.ftpserver.ftplet.FtpException;
import org.apache.ftpserver.ftplet.User;
import org.apache.ftpserver.ftplet.UserManager;
import org.apache.ftpserver.usermanager.AnonymousAuthentication;
import org.apache.ftpserver.usermanager.PasswordEncryptor;
import org.apache.ftpserver.usermanager.UsernamePasswordAuthentication;
import org.apache.ftpserver.usermanager.impl.AbstractUserManager;
import org.apache.ftpserver.usermanager.impl.BaseUser;
import org.apache.ftpserver.usermanager.impl.ConcurrentLoginPermission;
import org.apache.ftpserver.usermanager.impl.ConcurrentLoginRequest;
import org.apache.ftpserver.usermanager.impl.TransferRatePermission;
import org.apache.ftpserver.usermanager.impl.TransferRateRequest;
import org.apache.ftpserver.usermanager.impl.WritePermission;
import org.apache.ftpserver.usermanager.impl.WriteRequest;
import org.apache.ftpserver.util.StringUtils;

import static com.ztp.lib.server.UsersTableShema.*;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;

import com.example.ztpandroid233.SQLiteHelper;
import com.ztp.lib.server.Env;

public class AndroidDbUserManager extends AbstractUserManager {
	
	SQLiteHelper helper;
	public AndroidDbUserManager(SQLiteHelper helper, String adminName, PasswordEncryptor pw){
		super(adminName, pw);
		if(helper == null){
			throw new NullPointerException("SQLiteHelper helper == null");
		}
		this.helper = helper;
		SQLiteDatabase db = null;
		try{
			db = helper.getWritableDatabase();
			Cursor cursor = db.rawQuery("SELECT "+USERID_C+ " FROM "+ TBL_NAME+" WHERE "+USERID_C+"=?", new String[]{adminName});
			
			if(!cursor.moveToNext()){
				cursor.close();
				
				ContentValues values = new ContentValues();
				values.put(USERID_C		, adminName);
				values.put(USERPASS_C	, pw.encrypt(adminName));
				values.put(HOMEDIR_C	, Env.getHome());
				
				values.put(ENABLE_C		, 	true);
				values.put(WRITE_C		, 	true);
				values.put(IDLETIME_C	, 	0);
				
				values.put(UPRATE_C		, 	0);	
				values.put(DOWNRATE_C	, 	0);	
				
				values.put(MAXLOGIN_C		, 	0);
				values.put(MAXLOGINPERIP_C	, 	0);
				
				db.insert(TBL_NAME, null, values);
			}
			else{
				cursor.close();
			}
			
		}
		catch(SQLiteException e){
			throw new FtpServerConfigurationException("AndroidDbUserManager()" + e.getMessage());
		}
		finally{
			if(db != null && db.isOpen()){
				db.close();
			}
		}
	}
	
	@Override
	public User authenticate(Authentication a) throws AuthenticationFailedException {
		
		if(a instanceof UsernamePasswordAuthentication){
			UsernamePasswordAuthentication upa = (UsernamePasswordAuthentication) a;
			String user = upa.getUsername();
			String pass = upa.getPassword();
			
			if(user == null){
				throw new AuthenticationFailedException("username null");
			}
			if(pass == null){
				pass = "";
			}
			
			SQLiteDatabase db = null;
			
			try{	
				db = helper.getReadableDatabase();
				Cursor cursor = db.rawQuery(
						"SELECT " + USERPASS_C 
						+ " FROM " + TBL_NAME 
						+ " WHERE " + USERID_C +  "=?"
						
						, new String []{user}
					);
				if(cursor == null){
					throw new AuthenticationFailedException("AndroidDbUserManager.authenticate() cursor == null");
				}
				
				
				if(cursor.moveToNext()){
					if(getPasswordEncryptor().matches(pass, cursor.getString(0))){
						try {
							cursor.close();
							return getUserByName(user);
						} catch (FtpException e) {
							throw new AuthenticationFailedException("AuthenticationFailed 0");
						}
					}
					else{
						throw new AuthenticationFailedException("AuthenticationFailed 1");
					}
				}
				else{
					throw new AuthenticationFailedException("AuthenticationFailed 2");
				}
			}
			catch(SQLiteException e){
				throw new AuthenticationFailedException(e);
			}
		}
		else if(a instanceof AnonymousAuthentication){
			try {
				if(doesExist("anonymous")){
					return getUserByName("anonymous");
				}
				else{
					throw new AuthenticationFailedException("AuthenticationFailed 3");
				}
			} catch (FtpException e) {
				throw new AuthenticationFailedException("AuthenticationFailed 4");
			}
		}
		throw new AuthenticationFailedException("AuthenticationFailed 5");
	}

	@Override
	public void delete(String name) throws FtpException {
		SQLiteDatabase db = null;
		
		try{
			db = helper.getWritableDatabase();
			int rows = db.delete(TBL_NAME, USERID_C + "=?", new String[]{name});
			if(rows == 0){
				throw new FtpException("deleted 0 rows!");
			}
			else if(rows > 1){
				throw new FtpException("deleted "+rows+" rows!");
			}
			
		}
		catch (SQLiteException e) {
			throw new FtpException(e);
		}
		finally{
			if(db != null && db.isOpen()){
				db.close();
			}
		}
	}

	@Override
	public boolean doesExist(String name) throws FtpException {
		
		SQLiteDatabase db = null;
		try {
			db = helper.getReadableDatabase();
			
			Cursor cursor = db.rawQuery("SELECT "+USERID_C+" FROM "+TBL_NAME+" WHERE "+USERID_C+"=?"
					, new String[]{name});
			
			if(cursor != null){
				cursor.close();
				return (cursor.getCount() != 0)? true : false;
			}
			else{
				throw new FtpException("AndroidDbUserManager.doExist() cursor == null");
			}
			
		} catch (SQLiteException e) {
			throw new FtpException(e);
		}
	}

	@Override
	public String[] getAllUserNames() throws FtpException {
		SQLiteDatabase db = null;
		String [] users = null;
		
		try{
			db = helper.getReadableDatabase();
			Cursor cursor = db.rawQuery("SELECT " +USERID_C + " FROM" +TBL_NAME,null);
			if(cursor == null){
				throw new FtpException("AndroidDbUserManager.getAllUserNames() cursor == null");
			}
			
			users = new String[cursor.getCount()];
			int idx = 0;
			while(cursor.moveToNext()){
				users[idx++] = cursor.getString(0);
			}
			cursor.close();
			return users;
		}
		catch (SQLiteException e) {
			throw new FtpException(e);
		}
		finally{
			if(db != null && db.isOpen()){
				db.close();
			}
		}
	}

	@Override
	public User getUserByName(String name) throws FtpException {
		BaseUser baseUser = new BaseUser();
		SQLiteDatabase db = null;
		try{
		
			db = helper.getReadableDatabase();
			
			Cursor cursor = db.rawQuery("SELECT * FROM " + TBL_NAME + " WHERE " + USERID_C + "=?"
					, new String[]{name});
			
			if(cursor == null){
				throw new FtpException("AndroidDbUserManager.getUserByName() cursor == null");
			}
			
			if(cursor.moveToNext()){
				baseUser.setName(			cursor.getString(	cursor.getColumnIndex(USERID_C)));
				baseUser.setPassword(		cursor.getString(	cursor.getColumnIndex(USERPASS_C)));
				baseUser.setHomeDirectory(	cursor.getString(	cursor.getColumnIndex(HOMEDIR_C)));
				
				int enabled = cursor.getInt(cursor.getColumnIndex(ENABLE_C));
				baseUser.setEnabled( (enabled != 0)? true : false );
				
				baseUser.setMaxIdleTime(	cursor.getInt(		cursor.getColumnIndex(IDLETIME_C)));
				
				ArrayList<Authority> authorities = new ArrayList<Authority>(3);
				
				int write = cursor.getInt(cursor.getColumnIndex(WRITE_C));
				if(write != 0){
					authorities.add(new WritePermission());
				}
				authorities.add(new ConcurrentLoginPermission(
								cursor.getInt(cursor.getColumnIndex(MAXLOGIN_C))
								, cursor.getInt(cursor.getColumnIndex(MAXLOGINPERIP_C))));
				
				authorities.add(new TransferRatePermission(
						cursor.getInt(cursor.getColumnIndex(DOWNRATE_C))
						, cursor.getInt(cursor.getColumnIndex(UPRATE_C))));
				baseUser.setAuthorities(authorities);
				
			}
			cursor.close();
		}
		catch(SQLiteException e){
			throw new FtpException(e);
		}
		finally{
			if(db != null && db.isOpen()){
				db.close();
			}
		}
		
		return baseUser;
	}

	@Override
	public boolean isAdmin(String name) throws FtpException {
		return name.equals(getAdminName());
	}

	@Override
	public void save(User user) throws FtpException {
		SQLiteDatabase db = null;
		
		String encryptedPass = user.getPassword();
		encryptedPass = getPasswordEncryptor().encrypt(encryptedPass);
		
		ContentValues values = new ContentValues();
		values.put(USERID_C		,	user.getName());
		values.put(USERPASS_C	, 	encryptedPass);
		values.put(HOMEDIR_C	, 	user.getHomeDirectory());
		values.put(ENABLE_C		, 	user.getEnabled());
		values.put(WRITE_C		, 	user.authorize(new WriteRequest()) != null);
		values.put(IDLETIME_C	, 	user.getMaxIdleTime());
		
		TransferRateRequest trr = new TransferRateRequest();
		trr = (TransferRateRequest) user.authorize(trr);
		if(trr != null){
			values.put(UPRATE_C		, 	trr.getMaxUploadRate());	
			values.put(DOWNRATE_C	, 	trr.getMaxDownloadRate());	
		}
		else{
			values.put(UPRATE_C		, 	0);	
			values.put(DOWNRATE_C	, 	0);	
		}
		
		ConcurrentLoginRequest clr = new ConcurrentLoginRequest(0, 0);
		clr = (ConcurrentLoginRequest) user.authorize(clr);
		if(clr != null){
			values.put(MAXLOGIN_C		, 	clr.getMaxConcurrentLogins());
			values.put(MAXLOGINPERIP_C	, 	clr.getMaxConcurrentLoginsPerIP());
		}
		else{
			values.put(MAXLOGIN_C		, 	0);
			values.put(MAXLOGINPERIP_C	, 	0);
		}
		
		try {
			
			db = helper.getWritableDatabase();
			db.insertOrThrow(TBL_NAME, null, values);
			
			
		} catch (SQLiteException e) {
			throw new FtpException(e);
		}
		finally{
			if(db != null && db.isOpen()){
				db.close();
			}
		}
				
	}
	
}
